package com.nytimes.ohos.store.sample.data.model;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;

/**
 * Immutable implementation of {@link RedditData}.
 * <p>
 * Use the builder to create immutable instances:
 * {@code ImmutableRedditData.builder()}.
 */
@SuppressWarnings("all")
public final class ImmutableRedditData extends RedditData {
  private final Data data;
  private final String kind;

  private ImmutableRedditData(Data data, String kind) {
    this.data = data;
    this.kind = kind;
  }

  /**
   * data
   *
   * @return The value of the {@code data} attribute
   */
  @Override
  public Data data() {
    return data;
  }

  /**
   * kind
   *
   * @return The value of the {@code kind} attribute
   */
  @Override
  public String kind() {
    return kind;
  }

  /**
   * Copy the current immutable object by setting a value for the {@link RedditData#data() data} attribute.
   * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}.
   *
   * @param data A new value for data
   * @return A modified copy of the {@code this} object
   */
  public final ImmutableRedditData withData(Data data) {
    if (this.data == data) return this;
    Data newValue = Preconditions.checkNotNull(data, "data");
    return new ImmutableRedditData(newValue, this.kind);
  }

  /**
   * Copy the current immutable object by setting a value for the {@link RedditData#kind() kind} attribute.
   * An equals check used to prevent copying of the same value by returning {@code this}.
   *
   * @param kind A new value for kind
   * @return A modified copy of the {@code this} object
   */
  public final ImmutableRedditData withKind(String kind) {
    if (this.kind.equals(kind)) return this;
    String newValue = Preconditions.checkNotNull(kind, "kind");
    return new ImmutableRedditData(this.data, newValue);
  }

  /**
   * This instance is equal to all instances of {@code ImmutableRedditData} that have equal attribute values.
   *
   * @param another Object
   * @return {@code true} if {@code this} is equal to {@code another} instance
   */

  @Override
  public boolean equals(Object another) {
    if (this == another) return true;
    return another instanceof ImmutableRedditData
        && equalTo((ImmutableRedditData) another);
  }

  private boolean equalTo(ImmutableRedditData another) {
    return data.equals(another.data)
        && kind.equals(another.kind);
  }

  /**
   * Computes a hash code from attributes: {@code data}, {@code kind}.
   *
   * @return hashCode value
   */
  @Override
  public int hashCode() {
    int h = 31;
    h = h * 17 + data.hashCode();
    h = h * 17 + kind.hashCode();
    return h;
  }

  /**
   * Prints the immutable value {@code RedditData} with attribute values.
   *
   * @return A string representation of the value
   */
  @Override
  public String toString() {
    return MoreObjects.toStringHelper("RedditData")
        .omitNullValues()
        .add("data", data)
        .add("kind", kind)
        .toString();
  }

  /**
   * Creates an immutable copy of a {@link RedditData} value.
   * Uses accessors to get values to initialize the new immutable instance.
   * If an instance is already immutable, it is returned as is.
   *
   * @param instance The instance to copy
   * @return A copied immutable RedditData instance
   */
  public static ImmutableRedditData copyOf(RedditData instance) {
    if (instance instanceof ImmutableRedditData) {
      return (ImmutableRedditData) instance;
    }
    return ImmutableRedditData.builder()
        .from(instance)
        .build();
  }

  /**
   * Creates a builder for {@link ImmutableRedditData ImmutableRedditData}.
   *
   * @return A new ImmutableRedditData builder
   */
  public static Builder builder() {
    return new Builder();
  }

  /**
   * Builds instances of type {@link ImmutableRedditData ImmutableRedditData}.
   * Initialize attributes and then invoke the {@link #build()} method to create an
   * immutable instance.
   * <p><em>{@code Builder} is not thread-safe and generally should not be stored in a field or collection,
   * but instead used immediately to create instances.</em>
   */
  public static final class Builder {
    private static final long INIT_BIT_DATA = 0x1L;
    private static final long INIT_BIT_KIND = 0x2L;
    private long initBits = 0x3L;

    private Data data;
    private String kind;

    private Builder() {
    }

    /**
     * Fill a builder with attribute values from the provided {@code RedditData} instance.
     * Regular attribute values will be replaced with those from the given instance.
     * Absent optional values will not replace present values.
     *
     * @param instance The instance from which to copy values
     * @return {@code this} builder for use in a chained invocation
     */
    public final Builder from(RedditData instance) {
      Preconditions.checkNotNull(instance, "instance");
      data(instance.data());
      kind(instance.kind());
      return this;
    }

    /**
     * Initializes the value for the {@link RedditData#data() data} attribute.
     *
     * @param data The value for data 
     * @return {@code this} builder for use in a chained invocation
     */
    public final Builder data(Data data) {
      this.data = Preconditions.checkNotNull(data, "data");
      initBits &= ~INIT_BIT_DATA;
      return this;
    }

    /**
     * Initializes the value for the {@link RedditData#kind() kind} attribute.
     *
     * @param kind The value for kind 
     * @return {@code this} builder for use in a chained invocation
     */
    public final Builder kind(String kind) {
      this.kind = Preconditions.checkNotNull(kind, "kind");
      initBits &= ~INIT_BIT_KIND;
      return this;
    }

    /**
     * Builds a new {@link ImmutableRedditData ImmutableRedditData}.
     *
     * @return An immutable instance of RedditData
     * @throws IllegalStateException if any required attributes are missing
     */
    public ImmutableRedditData build() {
      if (initBits != 0) {
        throw new IllegalStateException(formatRequiredAttributesMessage());
      }
      return new ImmutableRedditData(data, kind);
    }

    private String formatRequiredAttributesMessage() {
      List<String> attributes = Lists.newArrayList();
      if ((initBits & INIT_BIT_DATA) != 0) attributes.add("data");
      if ((initBits & INIT_BIT_KIND) != 0) attributes.add("kind");
      return "Cannot build RedditData, some of required attributes are not set " + attributes;
    }
  }
}
